package com.iims.flowable.factory;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.iims.common.exception.CustomException;
import com.iims.common.utils.spring.SpringUtils;
import com.iims.common.vo.BusinessInfo;
import com.iims.common.vo.CreateUseInfo;
import com.iims.flowable.common.constant.FlowableConstant;
import com.iims.flowable.flow.ObjectUtils;
import com.iims.flowable.flow.domain.FlowBusinessConf;
import com.iims.flowable.flow.domain.FlowBusinessHistory;
import com.iims.flowable.flow.domain.FlowTaskForm;
import com.iims.flowable.flow.domain.FlowTaskNodeConf;
import com.iims.flowable.mapper.FlowBusinessConfMapper;
import com.iims.flowable.service.impl.FlowTaskFormServiceImpl;
import lombok.SneakyThrows;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.impl.cmd.SetProcessInstanceBusinessKeyCmd;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Date;

/**
 * 业务数据处理助手
 *
 * @author fanpei
 * @date 2021/7/16 16:11
 */
@Component
public class FlowBusinessUtils {

    @Autowired
    private FlowTaskFormServiceImpl cmistaskFormService;
    @Autowired
    private FlowBusinessConfMapper handleConfMapper;


    //flowable service
    @Autowired
    private ManagementService managementService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    protected HistoryService historyService;

    /**
     * 初始化业务 forKey | 默认为 FlowableConstant.PROCESS_INSTANCE_FORM_DATA
     *
     * @param processInstanceId
     * @param processDefKey
     * @return
     */
    @SneakyThrows
    public void initBusinessKey(String processInstanceId, String processDefKey) {
        //查询业务流程配置信息
        FlowBusinessConf businessConf = handleConfMapper.selectFlowBusinessConf(processDefKey);
        //流程未配置业务key生成 此处不处理
        if (ObjectUtil.isNotEmpty(businessConf)) {
            //获取初始化表单
            FlowTaskForm taskForm = cmistaskFormService.getRenderedTaskFormWithDataJson(processInstanceId, FlowableConstant.PROCESS_INSTANCE_FORM_DATA);
            if (ObjectUtil.isEmpty(taskForm)) {
                throw new CustomException("起始表单数据为空");
            }
            Class<?> clazz = Class.forName(businessConf.getBusinessKeyGenerateClass());
            Object genClassObj = SpringUtils.getBean(clazz);
            Method method = genClassObj.getClass().getMethod(businessConf.getBusinessKeyGenerateMethod(), String.class);
            BusinessInfo businessInfo = (BusinessInfo) method.invoke(genClassObj, taskForm.formDataJsonStr());
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .processInstanceBusinessKey(businessInfo.getBusinessKey()).singleResult();
            if (processInstance == null) {
                SetProcessInstanceBusinessKeyCmd businessKeyCmd = new SetProcessInstanceBusinessKeyCmd(processInstanceId, businessInfo.getBusinessKey());
                managementService.executeCommand(businessKeyCmd);
            }

            //插入业务key与流程的绑定关系
            FlowBusinessHistory businessHistory = new FlowBusinessHistory();
            businessHistory.setFlowDefKey(processDefKey);
            businessHistory.setFlowBusinessType(businessConf.getFlowBusinessType());
            businessHistory.setFlowBusinessKey(businessInfo.getBusinessKey());
            businessHistory.setFlowBusinessTargetId(businessInfo.getTargetId());
            businessHistory.setFlowGetBusinessClass(businessInfo.getBusinessClass());
            businessHistory.setFlowGetBusinessMethod(businessInfo.getBusinessMethod());
            handleConfMapper.insertFlowBusinessHistoryNotExist(businessHistory);
        }
    }

    /**
     * 新增或更新业务数据
     *
     * @param processInstanceId
     * @param processDefKey
     * @param formKey
     */
    @SneakyThrows
    public void doBusinessHandle(String processInstanceId, String processDefKey, String formKey) {
        FlowTaskNodeConf handleConf = handleConfMapper.selectFlowTaskByHandleKey(processDefKey, formKey);
        //需要处理表单数据
        if (null != handleConf) {
            FlowTaskForm taskForm = cmistaskFormService.getRenderedTaskFormWithDataJson(processInstanceId, handleConf.getFormKey());
            Class<?> clazz = Class.forName(handleConf.getHandleClass());
            Object service = SpringUtils.getBean(clazz);
            //反射调用数据入库【方法内部产生对象操作记录】
            Class<?> methodArgClass = Class.forName(handleConf.getHandleMethodEntity());
            Method method = service.getClass().getMethod(handleConf.getHandleMethod(), methodArgClass, CreateUseInfo.class);
            Object targetObjEntity = JSONUtil.toBean(taskForm.formDataJsonStr(), methodArgClass);
            //initCreateUpdateBy(targetObjEntity, taskForm);
            //初始化创建者更新者信息
            CreateUseInfo createUseInfo = new CreateUseInfo();
            createUseInfo.setCreateBy(taskForm.getCreateBy());
            createUseInfo.setCreateTime(taskForm.getCreateTime());
            method.invoke(service, targetObjEntity, createUseInfo);
        }
    }


    /**
     * 初始化创建者和更新者
     *
     * @param targetObjEntity
     * @param taskForm
     */
    @SneakyThrows
    @Deprecated
    private void initCreateUpdateBy(Object targetObjEntity, FlowTaskForm taskForm) {
        Method getCreateByMethod = targetObjEntity.getClass().getMethod("getCreateBy");
        //region 处理创建人信息
        if (ObjectUtils.isEmpty(getCreateByMethod.invoke(targetObjEntity))) {
            Method setCreateByMethod = targetObjEntity.getClass().getMethod("setCreateBy", String.class);
            Method setCreateTimeMethod = targetObjEntity.getClass().getMethod("setCreateTime", Date.class);
            setCreateByMethod.invoke(targetObjEntity, taskForm.getCreateBy());
            setCreateTimeMethod.invoke(targetObjEntity, new Date());
        }

        Method getUpdateByMethod = targetObjEntity.getClass().getMethod("getUpdateBy");
        //region 处理创建人信息
        if (ObjectUtils.isEmpty(getUpdateByMethod.invoke(targetObjEntity))) {
            Method setUpdateMethod = targetObjEntity.getClass().getMethod("setUpdateBy", String.class);
            setUpdateMethod.invoke(targetObjEntity, taskForm.getCreateBy());
        }
        Method setUpdateTimeMethod = targetObjEntity.getClass().getMethod("setUpdateTime", Date.class);
        setUpdateTimeMethod.invoke(targetObjEntity, new Date());
    }

    /**
     * 获取历史流程业务数据
     *
     * @param flowBusinessType
     * @param flowBusinessTargetId
     * @return
     */
    public FlowBusinessHistory selectOneFlowBusinessHis(String flowBusinessType, Long flowBusinessTargetId) {
        return handleConfMapper.selectOneFlowBusinessHis(flowBusinessType, flowBusinessTargetId);
    }

    /**
     * 通过defKey/businessKey获取业务数据对象
     *
     * @param flowDefKey
     * @param businessKey
     * @return
     */
    @SneakyThrows
    public Object getBusinessObj(String flowDefKey, String businessKey) {
        if (StrUtil.isNotBlank(businessKey)) {
            FlowBusinessHistory businessHistory = handleConfMapper.selectOneFlowBusinessHisByflowDefBusinessKey(flowDefKey, businessKey);
            Class<?> clazz = Class.forName(businessHistory.getFlowGetBusinessClass());
            Object service = SpringUtils.getBean(clazz);
            Method method = service.getClass().getMethod(businessHistory.getFlowGetBusinessMethod(), Long.class);
            return method.invoke(service, businessHistory.getFlowBusinessTargetId());
        }
        return null;
    }

}
